package com.serv.common.base;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;

import com.jfinal.core.Controller;
import com.jfinal.core.JFinal;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.StrKit;
import com.jfinal.log.Log;
import com.serv.util.Condition;
import com.serv.util.SearchFilter;

public class BaseController extends Controller {
	private Log log = Log.getLog(BaseController.class);
	private final String userKey = "_USER_";
	
	public <T> T getSubject(){
		return getSessionAttr(userKey);
	}
	
	public BaseController setSubject(Object value){
		setSessionAttr(userKey,value);
		return this;
	}
	
	public BaseController resetSubject(){
		setSessionAttr(userKey,null);
		return this;
	}
	
	@SuppressWarnings("rawtypes")
	public <T extends BaseModel> List<T> getModels(Class<T> modelClass) {
        List<T> modelList = new ArrayList<T>();
        int size = getLargeIndex(getParaMap());
        for (int i = 0; i <= size; i++) {
            T model = getModel(modelClass, StrKit.firstCharToLowerCase(modelClass.getSimpleName()) + "s[" + i + "]");
            if (!modelIsEmpty(model)) {
                modelList.add(model);
            }
        }
        return modelList;
    }
	
	public boolean isPost(){
		return StrKit.equals(getRequest().getMethod(), "POST");
	}
	
	public boolean isGet(){
		return StrKit.equals(getRequest().getMethod(), "GET");
	}
	
	public boolean isAjax(){
		String requestType = getRequest().getHeader("X-Requested-With");
		return "XMLHttpRequest".equals(requestType);
	}
	
	public String getEncodingPara(String paraName){
		String param = getPara(paraName);
		if(StrKit.isBlank(param)) return "";
		String encoding = JFinal.me().getConstants().getEncoding();
		try {
			return new String(param.getBytes("ISO-8859-1"),encoding);
		} catch (UnsupportedEncodingException e) {
			return "";
		}
	}
	
	public String getIpAddr(){
		HttpServletRequest request = getRequest();
        String ipAddress = request.getHeader("x-forwarded-for");
        String UNKNOWN = "unknown";
        if(StrKit.isBlank(ipAddress) || UNKNOWN.equalsIgnoreCase(ipAddress)) {  
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        
        if(StrKit.isBlank(ipAddress) || UNKNOWN.equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        
        if(StrKit.isBlank(ipAddress) || UNKNOWN.equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
            if(ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")){
                //根据网卡取本机配置的IP
                InetAddress inet=null;
                try {
                    inet = InetAddress.getLocalHost();
                } catch (UnknownHostException e) {
                    log.error("获取主机地址异常",e);
                }
                
                if(inet == null) return null;
                
                ipAddress= inet.getHostAddress();
            }
        }
        //对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割  
        if(ipAddress!=null && ipAddress.length()>15){ //"***.***.***.***".length() = 15  
            if(ipAddress.indexOf(",")>=0){
                ipAddress = ipAddress.substring(0,ipAddress.indexOf(','));
            }
        }
        return ipAddress;   
    }
	
	/**
	 * 取得带相同前缀的Request Parameters, copy from spring WebUtils.
	 * 
	 * 返回的结果的Parameter名已去除前缀.
	 */
	@SuppressWarnings("rawtypes")
	private Map<String, Object> getParametersStartingWith(String prefix) {
		HttpServletRequest request = getRequest();
		Enumeration paramNames = request.getParameterNames();
		Map<String, Object> params = new TreeMap<>();
		if (prefix == null) {
			prefix = "";
		}
		while ((paramNames != null) && paramNames.hasMoreElements()) {
			String paramName = (String) paramNames.nextElement();
			if ("".equals(prefix) || paramName.startsWith(prefix)) {
				String unprefixed = paramName.substring(prefix.length());
				String[] values = request.getParameterValues(paramName);
				if ((values == null) || (values.length == 0)) {
					// Do nothing, no values found at all.
				} else if (values.length > 1) {
					params.put(unprefixed, values);
				} else {
					params.put(unprefixed, values[0]);
				}
			}
		}
		return params;
	}
	
	@SuppressWarnings("unchecked")
	private Set<SearchFilter> getSearchFilters() {
		HttpServletRequest request = getRequest();
		
		Map<String, Object> searchParams = getParametersStartingWith("search_");
		Map<String, SearchFilter> mapfilters = SearchFilter.parse(searchParams);
		Collection<SearchFilter> filters = mapfilters.values();
		
		Set<SearchFilter> set = new HashSet<SearchFilter>(filters);
		// 数据权限中的filter
		Collection<SearchFilter> nestFilters = 
				(Collection<SearchFilter>)request.getAttribute("$nest_dynamic_search$");
		if (nestFilters != null && !nestFilters.isEmpty()) {
			for (SearchFilter searchFilter : nestFilters) {
				set.add(searchFilter);
			}
		}
		
		return set;
	}
	
	public Condition getConditions(final SearchFilter...searchFilters){
		Set<SearchFilter> filterSet = getSearchFilters();
		for (SearchFilter searchFilter : searchFilters) {
			filterSet.add(searchFilter);
		}
		
		Condition condition = getConditions(filterSet);
		
		HttpServletRequest request = getRequest();
		String orderField = request.getParameter("orderField");
		String orderDirection = request.getParameter("orderDirection");
		if(StrKit.isBlank(orderField)) return condition;
		
		if(StrKit.isBlank(orderDirection)) orderDirection = "asc";
		condition.setOrderBy(" order by " + orderField + " " + orderDirection);
		return condition;
	}
	
	private Condition getConditions(Set<SearchFilter> filterSet){
		StringBuilder conditions = new StringBuilder();
		List<Object> paramList = new ArrayList<>();
		for (SearchFilter filter : filterSet) {
			switch (filter.getOperator()) {
			case EQ:
				conditions.append(filter.getFieldName() + "=? and ");
				paramList.add(filter.getValue());
				break;
			case NE:
				conditions.append(filter.getFieldName() + "!=? and ");
				paramList.add(filter.getValue());
				break;
			case LIKE:
				conditions.append(filter.getFieldName() + " like ? and ");
				paramList.add("%" + filter.getValue() + "%");
				break;
			case GT:
				conditions.append(filter.getFieldName() + ">? and ");
				paramList.add(filter.getValue());
				break;
			case LT:
				conditions.append(filter.getFieldName() + "<? and ");
				paramList.add(filter.getValue());
				break;
			case GTE:
				conditions.append(filter.getFieldName() + ">=? and ");
				paramList.add(filter.getValue());
				break;
			case LTE:
				conditions.append(filter.getFieldName() + "<=? and ");
				paramList.add(filter.getValue());
				break;
			case IN:
				Object[] value = (Object[])filter.getValue();
				if(value.length > 0){
					StringBuilder sb = new StringBuilder();
					for (Object object : value) {
						sb.append("'"+object + "',");
					}
					
					String str = sb.toString();
					str = str.substring(0,str.length() - 1);
					conditions.append(filter.getFieldName() + " in (?) and ");
					paramList.add(str);
				}
				
				break;
			case ISNULL:
				conditions.append(filter.getFieldName() + " is null and ");
				break;

			case ISNOTNULL:
				conditions.append(filter.getFieldName() + " is not null and ");
				break;
			}
		}
		
		String conds = conditions.toString();
		if(conds.length() > 4) conds = conds.substring(0,conds.length() - 4);
		Object[] params = new Object[paramList.size()];
		paramList.toArray(params);
		
		return new Condition(conds,params);
	}
	
	public Map<String,String> getSimpleParaMap() {
		Map<String, String[]> properties = getParaMap();
		Map<String, String> returnMap = new HashMap<>();
		String name = "";
		String value = "";
		for (Map.Entry<String, String[]> entry : properties.entrySet()) {
			name = entry.getKey();
			String[] values = entry.getValue();
			if (null == values) {
				value = "";
			} else if (values.length>1) {
				for (int i = 0; i < values.length; i++) {
					value = values[i] + ",";
				}
				value = value.substring(0, value.length() - 1);
			} else {
				value = values[0];
			}
			returnMap.put(name, value);
		}
		return returnMap;
	}
	
	public int getLargeIndex(Map<String, String[]> map) {
        int max = 0;
        if (map != null) {
        	//key = xxx[0].yyy
            for (String key : map.keySet()) {
            	//tmp = {xxx[0],yyy}
            	String[] tmp = key.split("\\.");
            	if(tmp.length != 2) continue;
            	tmp = tmp[0].split("\\["); // tmp = {xxx,0]}
            	String num = tmp[1].substring(0,tmp[1].length() - 1); //num = 0
            	
                int index = Integer.parseInt(num);
                if(index > max) {
                    max = index;
                }
            }
        }
        return max;
    }
	
	public String collectorLogsPath(){
		String path = getSession().getServletContext().getRealPath("");
		path += File.separator+"WEB-INF"+File.separator+"collectorLogs"+File.separator;
		return path;
	}
	
	public String logPath(){
		return PropKit.get("log.dir");
	}
	
	@SuppressWarnings("rawtypes")
	private boolean modelIsEmpty(BaseModel model) {
        if (model == null) {
            return true;
        }
        
        return model.isEmpty();
    }
}
